/*
 * @Author: Jarvis 1405191257@qq.com
 * @Date: 2025-04-09 16:45:13
 * @LastEditors: Jarvis 1405191257@qq.com
 * @LastEditTime: 2025-04-09 19:16:04
 * @FilePath: /flash_hovercar_app/main.go
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"runtime"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
)

// 固件信息结构
type Firmware struct {
	Name string
	URL  string
}

// 定义固件列表
var firmwares = []Firmware{
	{Name: "主控分支", URL: "https://gitee.com/jarvisjia/flash_hover_car_app/releases/download/1.0.1/main.bin"},
	{Name: "显示分支", URL: "https://gitee.com/jarvisjia/flash_hover_car_app/releases/download/1.0.1/display.bin"},
	{Name: "电机分支", URL: "https://gitee.com/jarvisjia/flash_hover_car_app/releases/download/1.0.1/motor.bin"},
	{Name: "电池分支", URL: "https://gitee.com/jarvisjia/flash_hover_car_app/releases/download/1.0.1/battery.bin"},
}

// 检查是否安装了 st-flash
func checkStFlash() bool {
	var cmd *exec.Cmd
	if runtime.GOOS == "windows" {
		cmd = exec.Command("where", "st-flash.exe")
	} else {
		cmd = exec.Command("which", "st-flash")
	}
	return cmd.Run() == nil
}

// 获取安装指导
func getInstallGuide() string {
	switch runtime.GOOS {
	case "linux":
		return "请使用以下命令安装 st-flash：\n\n" +
			"Ubuntu/Debian:\n" +
			"sudo apt-get install stlink-tools\n\n" +
			"Fedora:\n" +
			"sudo dnf install stlink\n\n" +
			"Arch Linux:\n" +
			"sudo pacman -S stlink"
	case "windows":
		return "Windows 安装步骤：\n\n" +
			"1. 访问 https://github.com/stlink-org/stlink/releases\n" +
			"2. 下载最新的 Windows ZIP 包\n" +
			"3. 解压到任意目录\n" +
			"4. 将解压目录添加到系统环境变量 PATH 中\n\n" +
			"或者使用 Chocolatey 包管理器安装：\n" +
			"choco install stlink-utility"
	default:
		return "请访问 https://github.com/stlink-org/stlink 获取安装指南"
	}
}

// 下载固件
func downloadFirmware(url string) (string, error) {
	fmt.Printf("[状态] 开始下载固件: %s\n", url)
	// 创建临时文件
	tmpFile, err := os.CreateTemp("", "firmware-*.bin")
	if err != nil {
		fmt.Printf("[错误] 创建临时文件失败: %v\n", err)
		return "", fmt.Errorf("创建临时文件失败: %v", err)
	}
	defer tmpFile.Close()

	// 下载文件
	fmt.Println("[状态] 正在发送HTTP请求...")
	resp, err := http.Get(url)
	if err != nil {
		fmt.Printf("[错误] 下载固件失败: %v\n", err)
		return "", fmt.Errorf("下载固件失败: %v", err)
	}
	defer resp.Body.Close()

	// 写入临时文件
	fmt.Println("[状态] 正在保存固件到临时文件...")
	_, err = io.Copy(tmpFile, resp.Body)
	if err != nil {
		fmt.Printf("[错误] 保存固件失败: %v\n", err)
		return "", fmt.Errorf("保存固件失败: %v", err)
	}
	fmt.Printf("[状态] 固件已保存到临时文件: %s\n", tmpFile.Name())

	return tmpFile.Name(), nil
}

func main() {
	app := app.New()
	app.Settings().SetTheme(theme.LightTheme())
	w := app.NewWindow("卡丁车固件烧录工具")
	w.SetPadded(false)
	w.SetMainMenu(nil)

	// 创建主要内容
	mainContent := widget.NewLabel("请选择要烧录的固件分支")
	mainContent.Alignment = fyne.TextAlignCenter
	mainContent.TextStyle = fyne.TextStyle{Bold: true}

	// 创建进度条
	progress := widget.NewProgressBar()
	progress.Hide()

	// 创建状态标签
	statusLabel := widget.NewLabel("")
	statusLabel.Alignment = fyne.TextAlignCenter
	statusLabel.Hide()

	// 创建按钮容器
	var buttons []*widget.Button
	buttonContainer := container.NewGridWithColumns(2)

	// 为每个固件创建按钮
	for _, fw := range firmwares {
		fw := fw // 创建局部变量避免闭包问题
		btn := widget.NewButton(fw.Name, func() {
			// 检查是否安装了 st-flash
			if !checkStFlash() {
				installGuide := getInstallGuide()
				confirmDialog := dialog.NewConfirm(
					"未检测到烧录工具",
					installGuide,
					func(install bool) {
						if install {
							if runtime.GOOS == "linux" {
								statusLabel.Show()
								statusLabel.SetText("正在安装 st-flash...")

								var cmd *exec.Cmd
								if _, err := exec.LookPath("apt-get"); err == nil {
									cmd = exec.Command("pkexec", "apt-get", "install", "-y", "stlink-tools")
								} else if _, err := exec.LookPath("dnf"); err == nil {
									cmd = exec.Command("pkexec", "dnf", "install", "-y", "stlink")
								} else if _, err := exec.LookPath("pacman"); err == nil {
									cmd = exec.Command("pkexec", "pacman", "-S", "--noconfirm", "stlink")
								}

								if cmd != nil {
									if err := cmd.Run(); err != nil {
										dialog.ShowError(fmt.Errorf("安装失败: %v", err), w)
										statusLabel.SetText("安装失败！")
									} else {
										dialog.ShowInformation("成功", "st-flash 安装成功！", w)
										statusLabel.SetText("安装成功！")
									}
								}
							} else if runtime.GOOS == "windows" {
								cmd := exec.Command("cmd", "/c", "start", "https://github.com/stlink-org/stlink/releases")
								cmd.Run()
							}
						}
					},
					w,
				)
				confirmDialog.SetConfirmText("安装")
				confirmDialog.SetDismissText("取消")
				confirmDialog.Show()
				return
			}

			// 禁用所有按钮
			for _, b := range buttons {
				b.Disable()
			}

			progress.Show()
			statusLabel.Show()
			progress.SetValue(0)
			statusLabel.SetText("正在下载固件...")

			// 在新的 goroutine 中执行下载和烧录
			go func() {
				defer func() {
					for _, b := range buttons {
						b.Enable()
					}
					fmt.Println("[状态] 按钮已重新启用")
				}()

				fmt.Printf("[状态] 开始下载固件: %s\n", fw.Name)
				// 下载固件
				tmpFile, err := downloadFirmware(fw.URL)
				if err != nil {
					fmt.Printf("[错误] 下载失败: %v\n", err)
					dialog.ShowError(err, w)
					statusLabel.SetText("下载失败！")
					return
				}
				fmt.Printf("[状态] 固件下载成功，临时文件: %s\n", tmpFile)
				defer os.Remove(tmpFile) // 完成后删除临时文件

				// 显示烧录进度
				progress.SetValue(0.5)
				statusLabel.SetText("正在烧录固件...")
				fmt.Println("[状态] 开始烧录固件...")

				// 执行烧录命令
				var cmd *exec.Cmd
				if runtime.GOOS == "windows" {
					cmd = exec.Command("st-flash.exe", "write", tmpFile, "0x8000000")
				} else {
					cmd = exec.Command("st-flash", "write", tmpFile, "0x8000000")
				}

				output, err := cmd.CombinedOutput()
				if err != nil {
					fmt.Printf("[错误] 烧录失败: %v\n%s\n", err, string(output))
					dialog.ShowError(fmt.Errorf("烧录失败: %v\n%s", err, string(output)), w)
					statusLabel.SetText("烧录失败！")
				} else {
					fmt.Printf("[状态] 烧录成功！输出:\n%s\n", string(output))
					dialog.ShowInformation("成功", "固件烧录成功！", w)
					statusLabel.SetText("烧录成功！")
				}
				progress.SetValue(1.0)
			}()
		})
		buttons = append(buttons, btn)
		buttonContainer.Add(btn)
	}

	// 创建版权信息
	copyrightLabel := widget.NewLabel("copyright 2023 by Jarvis\n" +
		"本工具仅供学习和研究使用，禁止用于商业用途！\n" +
		"联系方式: Email: 1405191257@qq.com  微信: JarvisJiaX")
	copyrightLabel.Alignment = fyne.TextAlignCenter

	// 创建主布局
	content := container.NewVBox(
		layout.NewSpacer(),
		container.NewHBox(layout.NewSpacer(), mainContent, layout.NewSpacer()),
		buttonContainer,
		container.NewHBox(layout.NewSpacer(), progress, layout.NewSpacer()),
		container.NewHBox(layout.NewSpacer(), statusLabel, layout.NewSpacer()),
		layout.NewSpacer(),
		container.NewHBox(layout.NewSpacer(), copyrightLabel, layout.NewSpacer()),
		layout.NewSpacer(),
	)

	w.SetContent(container.NewPadded(content))
	w.Resize(fyne.NewSize(800, 600))
	w.CenterOnScreen()
	w.SetFixedSize(true)
	w.ShowAndRun()
}
